home *** CD-ROM | disk | FTP | other *** search
- /* flashtst.c - flash memory utility routines test module */
-
- /*** THIS MODULE IS PROVIDED BEING PROVIDED ON THE C/C++ USER'S
- JOURNAL CODE DISK AS SAMPLE CODE ONLY -- IT WON'T COMPILE
- FOR YOU WITHOUT SOME CUSTOMIZING FOR YOUR IMPLEMENTATION ***/
-
- /***
- This module contains routines which test the routines in fmutl.c.
-
- fm_intro() performs some nice "start-up" stuff for utilities.
-
- fm_short_test() is a quick but destructive test, suitable for
- manufacturing to run when checking out a newly built unit.
-
- This module can optionally be built to include a "huge test" routine
- for algorithm confidence testing.
-
- This module can also optionally be built as a stand-alone utility which
- performs either the short or huge tests.
-
- NOTE: Each time flash memories are reprogrammed they slow down a
- little (erases and writes take longer). Thus, these tests should not
- be executed repeatedly, since the performance and useful life of the
- devices decreases with each test cycle.
-
- ***/
-
-
- #ifndef STANDALONE /* (allows this to be set on compile cmd) */
- #define STANDALONE 0 /* non-zero for FLASHTST utility */
- #endif
-
- #ifndef HUGE_TEST /* (allows this to be set on compile cmd) */
- #define HUGE_TEST 1 /* non-zero for Huge test version */
- #endif
-
-
- #include <string.h>
- #include "sword.h"
- #include "keyutl.h"
- #include "fmutl.h"
-
- extern long fm_tot_errs; /* in fmerrmsg.c */
-
- extern char FreeRAM[]; /* in freeram.s68 */
-
-
-
- /*****************************************************************************
- Delay for the indicated amount of time while checking for switches.
- Returns 0 if no switches pressed; set bits indicate switches pressed.
- *****************************************************************************/
-
- static unsigned char SwiDelay(delay)
- int delay;
- {
- unsigned char SwiState;
-
- SwiState = 0;
- while (delay > 0)
- {
- SwiState |= (~(SWITCH)) & 0x0f;
- Delay(10);
- delay -= 10;
- }
- return SwiState;
- }
-
-
-
- /*****************************************************************************
- Handle an error.
- *****************************************************************************/
-
- static void Err(c)
- char c;
- {
- fm_err_msg(c, 300, 9000);
- }
-
-
-
- /*****************************************************************************
- Reset chips, display device type and total size found; returns non-zero if
- any switches were used. The FMINFO structure is filled with data from an
- fm_status() call.
- *****************************************************************************/
-
- fm_intro(pFlash, pFMInfo, errchr, delay)
- unsigned short *pFlash; /* ptr to base of Flash Memory space */
- FMINFO *pFMInfo; /* ptr to structure to fill with flash data */
- char errchr; /* chr to use for errmsg display */
- int delay; /* msec to pause for caller's greeting display */
- {
- unsigned char Switches;
-
- /* this delay is to pause for the caller's greeting display: */
- Switches = SwiDelay(delay);
-
- /* reset chips and get info about them: */
- DspText("Reset...", 1, 0, 40);
- Switches |= SwiDelay(200);
- if (!fm_status(pFlash, pFMInfo))
- Err(errchr);
- DspText("Done", 1, 12, 4);
- Switches |= SwiDelay(1000);
-
- /* display mfr/device name string: */
- DspText("(2)", 1, 0, 40);
- DspText(pFMInfo->pDevName, 1, 4, 36);
- Switches |= SwiDelay(1500);
-
- /* display amount of flash found: */
- if (pFMInfo->TotalSize >= 1024*1024)
- { DspNum(pFMInfo->TotalSize / (1024*1024), 1, 0, 4);
- DspText("Mbytes total", 1, 4, 13);
- }
- else
- { DspNum(pFMInfo->TotalSize / 1024, 1, 0, 4);
- DspText("Kbytes total", 1, 4, 13);
- }
- Switches |= SwiDelay(2500);
-
- /* return switch status (0 = none pressed): */
- return Switches;
- }
-
-
-
- /*****************************************************************************
- Short flash memory test routine. THIS IS A DESTRUCTIVE TEST. The
- contents of flash memory contents are erased and rewritten 3 times.
- If the caller zeros the fm_tot_errs global before calling this routine,
- then fm_tot_errs can be used to check for errors.
- *****************************************************************************/
-
- void fm_short_test(pFlash, pFMInfo, pScratch)
- unsigned short *pFlash; /* ptr to base of Flash Memory space */
- FMINFO *pFMInfo; /* ptr to structure containing flash data */
- unsigned short *pScratch; /* ptr to buffer of pFMInfo->TotalSize bytes */
- {
- register volatile unsigned short *ptr, *ptr2, *pRam;
- register unsigned short act;
- register unsigned long randval, rval1, rval2;
-
- #if 0 /* just do one sector, for debugging/timing tests: */
- pFMInfo->TotalSize /= pFMInfo->NumSect_;
- #endif
-
- /* TEST #1: write zeros to all of flash memory: */
- DspText("#1: Writing 0s", 1, 0, 40);
- memset(pScratch, 0, pFMInfo->TotalSize);
- DspText("#1: Writing 0s...", 1, 0, 40);
- if (!fm_write(pFlash, pFlash, pScratch, pFMInfo->TotalSize, 0))
- Err('1');
-
- /* verify all zeros: */
- DspText("#1: Verifying...", 1, 0, 40);
- pRam = pScratch;
- ptr2 = pFlash + (pFMInfo->TotalSize >> 1);
- for (ptr = pFlash; ptr < ptr2; ++ptr)
- { act = *ptr;
- if (*pRam != act)
- { fm_error(ptr, *pRam, act, 0xE1);
- Err('1');
- }
- }
-
-
- /* TEST #2: write ones to all of flash memory: */
- DspText("#2: Writing 1s", 1, 0, 40);
- memset(pScratch, 0xff, pFMInfo->TotalSize);
- DspText("#2: Writing 1s...", 1, 0, 40);
- if (!fm_write(pFlash, pFlash, pScratch, pFMInfo->TotalSize, 0))
- Err('2');
-
- /* verify all ones: */
- DspText("#2: Verifying...", 1, 0, 40);
- pRam = pScratch;
- ptr2 = pFlash + (pFMInfo->TotalSize >> 1);
- for (ptr = pFlash; ptr < ptr2; ++ptr)
- { act = *ptr;
- if (*pRam != act)
- { fm_error(ptr, *pRam, act, 0xE2);
- Err('2');
- }
- }
-
-
- /* TEST 3: write rotating ones and zeros pattern (once): */
- DspText("#3: Rot 0s&1s", 1, 0, 40);
-
- /* fill first 17 slots with nice rotating numbers (and an all 1's): */
- ptr = pScratch;
- *ptr++ = 0xfe01;
- *ptr++ = 0xfd02;
- *ptr++ = 0xfb04;
- *ptr++ = 0xf708;
- *ptr++ = 0xef10;
- *ptr++ = 0xdf20;
- *ptr++ = 0xbf40;
- *ptr++ = 0x7f80;
- *ptr++ = 0xffff;
- for (act = 8; act; --act)
- { *ptr = *(ptr - 9) ^ 0xffff;
- ++ptr;
- }
-
- /* now duplicate this through the rest of our RAM buffer: */
- pRam = pScratch;
- ptr2 = pRam + (pFMInfo->TotalSize >> 1);
- while (ptr < ptr2)
- *ptr++ = *pRam++;
-
- /* write it out: */
- DspText("#3: Rot 0s&1s...", 1, 0, 40);
- if (!fm_write(pFlash, pFlash, pScratch, pFMInfo->TotalSize, 0))
- Err('3');
-
- /* verify the values: */
- DspText("#3: Verifying...", 1, 0, 40);
- pRam = pScratch;
- ptr2 = pFlash + (pFMInfo->TotalSize >> 1);
- for (ptr = pFlash; ptr < ptr2; ++ptr)
- { act = *ptr;
- if (*pRam++ != act)
- { fm_error(ptr, pRam[-1], act, 0xE3);
- Err('3');
- }
- }
-
-
- /* TEST #4: write, then read, random values: */
- DspText("#4: Unique data", 1, 0, 40);
- randval = 0; /* seed */
-
- /* fill RAM buffer with random values: */
- /* (random # fn is from The Standard C Library by P.J.Plauger, p359) */
- rval1 = 1103515245;
- rval2 = 12345;
- ptr2 = pScratch + (pFMInfo->TotalSize >> 1);
- for (ptr = pScratch; ptr < ptr2; ++ptr)
- { randval = randval * rval1 + rval2;
- *ptr = (unsigned short) (randval >> 16);
- }
-
- /* write it out: */
- DspText("#4: Unique data...", 1, 0, 40);
- if (!fm_write(pFlash, pFlash, pScratch, pFMInfo->TotalSize, 0))
- Err('4');
-
- /* verify the values: */
- DspText("#4: Verifying...", 1, 0, 40);
- pRam = pScratch;
- ptr2 = pFlash + (pFMInfo->TotalSize >> 1);
- for (ptr = pFlash; ptr < ptr2; ++ptr)
- { act = *ptr;
- if (*pRam++ != act)
- { fm_error(ptr, pRam[-1], act, 0xE4);
- Err('4');
- }
- }
-
-
- DspText("Done", 1, 0, 40);
- Delay(500);
- }
-
-
-
- #if HUGE_TEST
-
-
- /* (random # fn is from The Standard C Library by P.J.Plauger, p359) */
- #define RND1(x) ((x) * 1103515245 + 12345)
- #define RND2(x) ((x) >> 16)
- static unsigned long randval = 0;
-
-
- /*****************************************************************************
- Return a random value in the range [2,mask-1]. Mask should have lots of
- low bits set.
- *****************************************************************************/
-
- static unsigned RndOfs(mask)
- {
- unsigned offset;
-
- do
- { randval = RND1(randval);
- offset = RND2(randval) & mask;
- } while (offset == 0 || offset == 1 || offset == mask);
-
- return offset;
- }
-
-
-
- #define FM_ERASE_VAL 0xFFFF /* value of an erased location */
-
-
- /*****************************************************************************
- Huge flash memory test. An exhaustive battery of sector boundary
- write tests. THIS IS A DESTRUCTIVE TEST -- flash memory contents are
- erased. Rigorous boundary tests are performed using the fm_write()
- routine.
-
- This test runs 528 erase/write/verify cycles, checking all combinations
- of fm_write calls with varying start and end sector boundary conditions:
- - at the sector boundary
- - one word past the sector boundary
- - one word prior to the next sector boundary
- - one other random position within the sector
-
- This test takes about two hours to run. A running error total is shown on
- the display; error specifics are output using printf() calls.
- *****************************************************************************/
-
- void fm_huge_test(pBase, pFMInfo, pScratch)
- unsigned short *pBase; /* ptr to base of Flash Memory space */
- FMINFO *pFMInfo; /* ptr to filled in structure */
- unsigned short *pScratch; /* ptr to scratch sector storage area */
- {
- volatile unsigned short *ptr;
- unsigned short *pStart, *pEnd, *pScr0; /* pEnd is exclusive */
- unsigned short act, exp;
- int hi, lo, tstnum;
-
- /* carve out a section of scratch area for sector buffer: */
- pScr0 = pScratch;
- pScratch += (pFMInfo->SectorSize >> 1);
-
- /* init display and some other stuff: */
- tstnum = 0;
- DspText(" 0/528 no errs", 1, 0, 16);
- randval = 0; /* seed */
-
- /* outer loop: */
- for (lo = 0; lo <= 31; ++lo)
- {
- /* inner loop: */
- for (hi = lo + 1; hi <= 32; ++hi)
- {
- /* construct pStart pointer: */
- pStart = pBase + (lo / 4) * (pFMInfo->SectorSize >> 1);
- switch (lo & 3)
- {
- case 1: pStart += 1; break;
- case 2: pStart += RndOfs((pFMInfo->SectorSize >> 1) - 1);
- break;
- case 3: pStart += (pFMInfo->SectorSize >> 1) - 1;
- }
-
- /* construct pEnd pointer: */
- pEnd = pBase + (hi / 4) * (pFMInfo->SectorSize >> 1);
- switch (hi & 3)
- {
- case 1: pEnd += 1; break;
- case 2: pEnd += RndOfs((pFMInfo->SectorSize >> 1) - 1);
- break;
- case 3: pEnd += (pFMInfo->SectorSize >> 1) - 1;
- }
-
- /* cope with special cases of random pointers: */
- if ((lo & 3) == 2 && (hi & 3) == 2)
- if (pEnd == pStart)
- --pStart;
- else if (pStart > pEnd)
- { ptr = pEnd;
- pEnd = pStart;
- pStart = ptr;
- }
- DspNum(++tstnum, 1, 0, 3);
-
- /* "erase" whole chip: */
- ptr = pScratch + (pFMInfo->TotalSize >> 1);
- while (--ptr >= pScratch)
- *ptr = FM_ERASE_VAL;
- if (!fm_write(pBase, pBase, pScratch,
- pFMInfo->TotalSize, 0))
- Err('E');
-
- /* change buffer values to detect accidental use: */
- ptr = pScratch + (pFMInfo->TotalSize >> 1);
- while (--ptr >= pScratch)
- *ptr = ~FM_ERASE_VAL;
-
- /* fill an area of RAM with a random value: */
- randval = RND1(randval);
- act = RND2(randval);
- ptr = pScratch + (pEnd - pStart);
- while (--ptr >= pScratch)
- *ptr = act;
-
- #if 1 /* debug output, to help log errors: */
- printf("%3d: %08x %08x\n", tstnum,
- pStart - pBase, pEnd - pBase);
- #elif 0 /* this can be gnuplotted with errorbars: */
- printf("%3d %7d %7d %7d %08x %08x", tstnum, pStart - pBase,
- pStart - pBase, pEnd - pBase, pStart - pBase, pEnd - pBase);
- #endif
-
- /* write the RAM area to flash: */
- if (!fm_write(pBase, pStart, pScratch,
- (pEnd - pStart) << 1, pScr0))
- Err('W');
-
- /* verify any unwritten locations - after: */
- exp = FM_ERASE_VAL;
- ptr = pBase + ((pFMInfo->TotalSize >> 1) - 1);
- while (ptr >= pEnd)
- { if (*ptr != exp)
- { fm_error(ptr, exp, *ptr, 0xF2);
- Err('V');
- }
- --ptr;
- }
-
- /* verify written locations: */
- while (ptr >= pStart)
- { if (*ptr != act)
- { fm_error(ptr, act, *ptr, 0xF3);
- Err('V');
- }
- --ptr;
- }
-
- /* verify any unwritten locations - before: */
- while (ptr >= pBase)
- { if (*ptr != exp)
- { fm_error(ptr, exp, *ptr, 0xF4);
- Err('V');
- }
- --ptr;
- }
-
- /* update error counter on display: */
- if (fm_tot_errs)
- DspNum(fm_tot_errs, 1, 8,
- (fm_tot_errs <= 999 ? 3 : 4));
- }
- }
-
- /* all done: */
- VBeep(50); Delay(50);
- VBeep(50); Delay(50);
- VBeep(50); Delay(50);
- Delay(5000);
- }
-
-
- #endif
-
-
-
- #if STANDALONE
-
- static char VerStr[] = "FLASHTST Ver. 1D\n ";
-
- /* variables normally located in geint.s68: */
- long CTime = 0;
- long SeqNum = 0;
-
-
- main() /* downloadable utility to perform flash chip tests */
- {
- FMINFO FMInfo;
-
- #if HUGE_TEST
- /* provide a warning for this version: */
- DspWrite("WARNING: Huge\nflash mem test!!");
- VBeep(1000); Delay(4000);
- #endif
-
- /* say hello to the nice people: */
- DspWrite(VerStr);
- DspText("Flash mem. tests", 1, 0, 40);
- #if HUGE_TEST
- DspText("*FMHUGE*", 0, 0, 8);
- #endif
- VBeep(50); Delay(50); VBeep(50);
-
- /* init the output port: */
- InitRS();
-
- /* reset chips; display size: */
- fm_tot_errs = 0;
- fm_intro((unsigned short *) FLASHBASE, &FMInfo, 'S', 5000);
-
- /* ensure that we have enough free ram to do these tests: */
- #if HUGE_TEST
- if (FreeRAM + FMInfo.TotalSize > (char *) (RAMBASE + RAMSIZE))
- #else
- if (FreeRAM + FMInfo.SectorSize > (char *) (RAMBASE + RAMSIZE))
- #endif
- { DspText("ERROR: RAM OVFL", 1, 0, 40);
- while (1) { }
- }
-
- /* do the test: */
- #if HUGE_TEST
- fm_huge_test((unsigned short *) FLASHBASE, &FMInfo, (unsigned short *) FreeRAM);
- #else
- fm_short_test((unsigned short *) FLASHBASE, &FMInfo, (unsigned short *) FreeRAM);
- #endif
-
- /* display final error total: */
- DspWrite(VerStr);
- DspText("# errors:", 1, 0, 40);
- DspNum(fm_tot_errs, 1, 10, 6);
- VBeep(50); Delay(50);
- VBeep(50); Delay(50);
- VBeep(50); Delay(50);
-
- /* hang forever: */
- while (1) { }
- }
-
- #endif
-